package io.kiki.sba.registry.common.model.dataserver;


import io.kiki.sba.registry.common.model.store.Publisher;
import io.kiki.sba.registry.common.model.store.StringInterner;
import io.kiki.sba.registry.util.DatumVersionUtil;
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * datum store in dataserver
 */
public class Datum implements Serializable {

    private static final long serialVersionUID = 1L;
    // key=registerId
    private final Map<String, Publisher> registerIdToPublisherMap = new HashMap<>();
    @Getter
    private String dataInfoId;
    @Getter
    private String dataCenter;
    @Getter
    private String dataId;
    @Getter
    private String instanceId;
    @Getter
    private String group;
    @Setter
    @Getter
    private long version;

    @Setter
    @Getter
    private List recentVersions;


    public Datum() {
    }


    public Datum(String dataInfoId, String dataCenter) {
        this.dataInfoId = StringInterner.intern(dataInfoId);
        this.dataCenter = StringInterner.intern(dataCenter);
        this.recentVersions = Collections.EMPTY_LIST;
        updateVersion();
    }


    public Datum(Publisher publisher, String dataCenter) {
        this(publisher.getDataInfoId(), dataCenter);
        this.dataId = publisher.getDataId();
        this.instanceId = publisher.getInstanceId();
        this.group = publisher.getGroup();
        addPublisher(publisher);
    }

    public Datum(Publisher publisher, String dataCenter, long version) {
        this.dataInfoId = publisher.getDataInfoId();
        this.dataCenter = StringInterner.intern(dataCenter);
        this.version = version;
        this.dataId = publisher.getDataId();
        this.instanceId = publisher.getInstanceId();
        this.group = publisher.getGroup();
        this.recentVersions = Collections.EMPTY_LIST;
        addPublisher(publisher);
    }

    public void updateVersion() {
        if (DatumVersionUtil.useConfregVersionGen()) {
            this.version = DatumVersionUtil.confregNextId(0);
        } else {
            this.version = DatumVersionUtil.nextId();
        }
    }


    public void setDataInfoId(String dataInfoId) {
        this.dataInfoId = StringInterner.intern(dataInfoId);
    }


    public void setDataCenter(String dataCenter) {
        this.dataCenter = StringInterner.intern(dataCenter);
    }


    public void setDataId(String dataId) {
        this.dataId = StringInterner.intern(dataId);
    }


    public void setInstanceId(String instanceId) {
        this.instanceId = StringInterner.intern(instanceId);
    }


    public void setGroup(String group) {
        this.group = StringInterner.intern(group);
    }


    public synchronized boolean addPublisher(Publisher publisher) {
        Publisher existing = registerIdToPublisherMap.computeIfAbsent(publisher.getRegisterId(), k -> publisher);
        if (existing == publisher) {
            return true;
        }
        if (!existing.registerVersion().orderThan(publisher.registerVersion())) {
            return false;
        }
        registerIdToPublisherMap.put(publisher.getRegisterId(), publisher);
        return true;
    }

    public synchronized int publisherSize() {
        return registerIdToPublisherMap.size();
    }

    public synchronized void addPublishers(Map<String, Publisher> publisherMap) {
        if (publisherMap != null) {
            publisherMap.values().forEach(publisher -> addPublisher(publisher));
        }
    }

    public synchronized Map<String, Publisher> getRegisterIdToPublisherMap() {
        return Collections.unmodifiableMap(new HashMap<>(registerIdToPublisherMap));
    }

}
